<?PHP
/**
 * OpenStation
 *
 * @Application : Mysql.class.php
 * @Encode : 65001 Unicode ( UTF-8 NO BOM )
 * @Description : Mysql驱动类
 * @Author : HK <hkyyang@gmail.com>
 */

define( 'CLIENT_MULTI_RESULTS', 131072 );

class Mysql extends Db {

    /**
     *  构造方法
     *
     * @access public
     * @param Array | String : $config
     * @return void
     */
     public function __construct( $config = NULL ) {
        if( ! extension_loaded( 'mysql' ) ) {
            throw_exception( Cache :: lang( 'NOT_LOAD_EXTENSION' ) . ': MYSQL' );
        }
        $this -> dbType = strtoupper( __CLASS__ );
        if( ! empty( $config ) ) {
            $this -> config = $config;
        }
        $this -> initial();
     }

    /**
     *  connect 方法，连接数据库
     *
     * @access public
     * @param Array : $config
     * @param Integer : $link_num
     * @param Boolean : $retry
     * @return void
     */
     public function connect( $config = NULL, $link_num = 0, $retry = false ) {
        if( ! $retry ) {
            $this -> FailNum = 0;
        }
        if( ! isset( $this -> linkID[ $link_num ] ) ) {
            if( empty( $config ) ) {
                $config = $this -> config;
            }

            $db_host = $config[ 'host' ] . ( $config[ 'port' ] ? ":{$config[ 'port' ]}" : '' );
            if( $this -> pconnect ) {
                $this -> linkID[ $link_num ] = mysql_pconnect( $db_host, $config[ 'username' ], $config[ 'password' ], CLIENT_MULTI_RESULTS );
            } else {
                $this -> linkID[ $link_num ] = mysql_connect( $db_host, $config[ 'username' ], $config[ 'password' ], TRUE, CLIENT_MULTI_RESULTS );
            }
            if( ! $this -> linkID[ $link_num ] || ! empty( $this -> linkID[ $link_num ] ) && ! mysql_select_db( $config[ 'database' ], $this -> linkID[ $link_num ] ) ) {
                if( ++$this -> FailNum <= $this -> RetryNum ) {
                    Log :: sql_error( mysql_error(), Cache :: lang( 'DB_CONNECT_FAIL' ) . ': (' . $this -> FailNum . '), ' . str_replace( '%0', $this -> RetryWait, Cache :: lang( 'WAIT_TIME_RETRY' ) ) );
                    sleep( $this ->RetryWait );
                    $this -> linkID[ $link_num ] = NULL;
                    return $this -> connect( $config, $link_num, TRUE );
                }
                throw_exception( mysql_error() );
            }
            $version = mysql_get_server_info( $this -> linkID[ $link_num ] );
            if( $version >= '4.1' ) {
                mysql_query( "SET NAMES '{$config[ 'charset' ]}'", $this -> linkID[ $link_num ] );
            }
            if( $version > '5.0.1' ) {
                mysql_query( "SET sql_mode=''", $this -> linkID[ $link_num ] );
            }
            $this -> connected = TRUE;
        }
        return $this -> linkID[ $link_num ];
     }

    /**
     *  query 方法，执行查询
     *
     * @access public
     * @param String : $sqlStr
     * @return Boolean | Integer
     */
     public function query( $sqlStr ) {
        $this -> initConnect();
        if( ! $this -> link ) {
            return FALSE;
        }
        $this -> queryStr = $sqlStr;
        $this -> free();
        $this -> queryID = mysql_query( $this -> queryStr, $this -> link );
        if( $this -> queryID === FALSE ) {
            $this -> error();
            return FALSE;
        } else {
            $this -> numRows = mysql_num_rows( $this -> queryID );
            return $this -> fetch();
        }
     }

    /**
     *  fetch 方法，返回查询的数据
     *
     * @access public
     * @param String : $sqlStr
     * @return Boolean | Integer
     */
     public function fetch() {
        $result = array();
        if( $this -> numRows > 0 ) {
            while( $row = mysql_fetch_assoc( $this -> queryID ) ) {
                $result[] = $row;
            }
            mysql_data_seek( $this -> queryID , 0 );
        }
        return $result;
     }

    /**
     *  execute 方法，执行更新语句
     *
     * @access public
     * @param String : $sqlStr
     * @return Boolean | Integer
     */
    public function execute( $sqlStr ) {
        $this -> initConnect();
        if( ! $this -> link ) {
            return FALSE;
        }
        $this -> queryStr = $sqlStr;
        $this -> free();
        $result = mysql_query( $sqlStr, $this -> link );
        if( $result === FALSE ) {
            $this -> error();
            return FALSE;
        } else {
            $this -> numRows = mysql_affected_rows( $this -> link );
            $this -> lastInsertID = mysql_insert_id( $this -> link );
            return $this -> numRows;
        }
    }

    /**
     *  transaction 方法，启动事务
     *
     * @access public
     * @return Boolean
     */
    public function transaction() {
        $this -> initConnect();
        if( ! is_resource( $this -> link ) ) {
            return FALSE;
        }
        if( $this -> transNums == 0 ) {
            mysql_query( 'START TRANSACTION', $this -> link );
        }
        $this -> transNums ++;
        return TRUE;
    }

    /**
     *  commit 方法，提交当前事务
     *
     * @access public
     * @return Boolean
     */
    public function commit() {
        if( $this -> transNums > 0 ) {
            $result = mysql_query( 'COMMIT', $this -> link );
            $this -> transNums = 0;
            if( ! $result ) {
                throw_exception( $this -> error() );
            }
            return TRUE;
        }
        return FALSE;
    }

    /**
     *  rollback 方法，事务回滚
     *
     * @access public
     * @return Boolean
     */
     public function rollback() {
        if( $this -> transNums > 0 ) {
            $result = mysql_query( 'ROLLBACK', $this -> link );
            $this -> transNums = 0;
            if( ! $result ) {
                throw_exception( $this -> error() );
            }
            return TRUE;
        }
        return FALSE;
     }

    /**
     *  fetchAll 方法，返回查询的数据
     *
     * @access public
     * @return Array
     */
     public function fetchAll() {
        $result = array();
        if( $this -> numRows > 0 ) {
            while( $row = mysql_fetch_assoc( $this -> queryID ) ) {
                $result[] = $row;
            }
            mysql_data_seek( $this -> queryID, 0 );
        }
        return $result;
     }

    /**
     *  getFields 方法，获取数据表的字段信息
     *
     * @access public
     * @param String : $tbName, 表名称
     * @return Array
     */
     public function getFields( $tbName ) {
        $result = $this -> query( 'SHOW COLUMNS FROM ' . $tbName );
        $info = array();
        if( $result ) {
            foreach( $result as $v ) {
                $info[ $v[ 'Field' ] ] = array(
                    'name' => $v[ 'Field' ],
                    'type' => $v[ 'Type' ],
                    'notnull' => ( Bool ) ( $v[ 'Null' ] === '' ),
                    'default' => $v[ 'Default' ],
                    'primary' => ( strtolower( $v[ 'Key' ] ) == 'pri' ),
                    'autoinc' => ( strtolower( $v[ 'Extra' ] == 'auto_increment' ) )
                );
            }
        }
        return $info;
     }

    /**
     *  getTables 方法，获取数据库的表信息
     *
     * @access public
     * @param String : $tbName, 表名称
     * @return Array
     */
    public function getTables( $dbName ) {
        $sql = 'SHOW TABLES ';
        if( ! empty( $dbName ) ) {
            $sql .= 'FROM ' . $dbName;
        }
        $result = $this -> query( $sql );
        $info = array();
        foreach( $result as $k => $v ) {
            $info[ $k ] = current( $v );
        }
        return $info;
    }

    /**
     *  insert 方法，插入记录
     *
     * @access public
     * @param * : $datas, 数据
     * @param Array : $option, 参数
     * @return Integer
     */
    public function insert( $datas, $options = array() ) {
        if( ! is_array( $datas [ 0 ] ) ) {
            return FALSE;
        }
        $fileds = array_keys( $datas[ 0 ] );
        array_walk( $fileds, array( $this, 'addSpecialChar' ) );
        $values = array();
        foreach( $datas as $data ) {
            $value = array();
            foreach( $data as $v ) {
                $v = $this -> parseValue( $v );
                if( is_scalar( $v ) ) {
                    $value[] = $v;
                }
            }
            $values[] = '(' . implode( ',', $value ) . ')';
        }
        $sql = 'INSERT INTO ' . $this -> parseTable( $options[ 'table' ] ) . ' (' . implode( ',', $fileds ) . ') VALUES ' . implode( ',', $values );
        return $this -> execute( $sql );
    }

    /**
     *  replace 方法，替换插入记录
     *
     * @access public
     * @param * : $data, 数据
     * @param Array : $option, 参数
     * @return Integer
     */
    public function replace( $data, $options = array() ) {
        foreach( $data as $k => $v ) {
            $value = $this -> parseValue( $v );
            if( is_scalar( $value ) ) {
                $values[] = $value;
                $fileds[] = $this -> addSpecialChar( $k );
            }
        }
        $sql = 'REPLACE INTO ' . $this -> parseTable( $options[ 'table' ] ) . '(' . implode( ',', $fileds ) . ') VALUES (' . implode( ',', $values ) . ')';
        return $this -> execute( $sql );
    }

    /**
     *  close 方法，关闭数据库
     *
     * @access public
     * @param * : $data, 数据
     * @param Array : $option, 参数
     * @return Integer
     */
    public function close() {
        $this -> free();
        if ( is_resource( $this -> link ) && ! mysql_close( $this -> link ) ) {
            throw_exception( $this->error() );
        }
        if( in_array( $this -> link, $this -> linkID, TRUE ) ) {
            unset( $this -> linkID[ array_search( $this -> link, $this -> linkID, TRUE ) ] );
            $this -> connected = FALSE;
            $this -> link = NULL;
        }
    }

    /**
     *  free 方法，释放查询结果
     *
     * @access public
     * @return void
     */
    public function free() {
        if( is_resource( $this -> queryID ) ) {
            mysql_free_result( $this -> queryID );
        }
        $this -> queryID = NULL;
    }

    /**
     *  escape_string方法，SQL字符串过滤
     *
     * @access public
     * @return void
     */
    public function escape_string( $str ) {
        return mysql_escape_string( $str );
    }

    /**
     *  error 方法，获取错误
     *
     * @access public
     * @return String
     */
     private function error() {
        if( ! is_resource( $this -> link ) ) {
            return FALSE;
        }
        return $this -> error = mysql_error( $this -> link );
     }

    /**
     *  析构方法，关闭数据库
     *
     * @access public
     * @return void
     */
    public function __destruct(  ) {
        $this -> close();
    }

}

?>